/* 功能： 创建一幅24位真彩色位图
** 作者： mayadong7349
** 参考： MSDN(Visual Studio 2005)、（百度百科：bmp） http://baike.baidu.com/view/7671.htm#2
*/
// #include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bitmap.h"

#define BMP_W 640L
#define BMP_H 480L

void SetBmpInfoHeader(PBITMAPINFOHEADER pbmpih, int width, int height, int biBitCount)
{
	/* 14~17： 本结构体所占字节数， 固定值40 
	MSDN: Specifies the number of bytes required by the structure. 
	*/
	pbmpih->biSize          = 40;
	/* 18~21: 位图的宽度（以像素pixel为单位） 
	MSDN: Specifies the width of the bitmap, in pixels. 
	Windows 98/Me, Windows 2000/XP: If biCompression is BI_JPEG or BI_PNG, the biWidth member specifies 
	                                the width of the decompressed JPEG or PNG image file, respectively. 
	*/
	pbmpih->biWidth         = width;  
	/* 22~25: 位图的高度 
	MSDN: Specifies the height of the bitmap, in pixels. If biHeight is positive, the bitmap is a 
	bottom-up DIB and its origin is the lower-left corner. If biHeight is negative, the bitmap is 
	a top-down DIB and its origin is the upper-left corner. 
	If biHeight is negative, indicating a top-down DIB, biCompression must be either BI_RGB or 
	BI_BITFIELDS. Top-down DIBs cannot be compressed. 
	Windows 98/Me, Windows 2000/XP: If biCompression is BI_JPEG or BI_PNG, the biHeight member specifies 
	                                the height of the decompressed JPEG or PNG image file, respectively. 
	*/
	pbmpih->biHeight        = height;  
	/* 26~27: 目标设备的级别, 固定值：1 
	MSDN: Specifies the number of planes for the target device. This value must be set to 1*/
	pbmpih->biPlanes        = 1;   
	/* 28~29: 一个像素所占bit数， 可以是：1（双色）、4（16色）、8（256色）
	、16（65536色）、24（真彩色2^24种颜色）、32（真彩色2^32种颜色），具体参阅MSDN。
	对于24位真彩色位图， 一个像素占用三个字节,即24 bits 
	MSDN: Specifies the number of bits-per-pixel. The biBitCount member of the BITMAPINFOHEADER
	      structure determines the number of bits that define each pixel and the maximum number 
		  of colors in the bitmap. This member must be one of the following values. 
    0: Windows 98/Me, Windows 2000/XP: The number of bits-per-pixel is specified or is implied 
	   by the JPEG or PNG format.  
    1: The bitmap is monochrome, and the bmiColors member of BITMAPINFO contains two entries. 
	   Each bit in the bitmap array represents a pixel. If the bit is clear, the pixel is displayed
	   with the color of the first entry in the bmiColors table; if the bit is set, the pixel has 
	   the color of the second entry in the table. 
    4: The bitmap has a maximum of 16 colors, and the bmiColors member of BITMAPINFO contains up to 
	   16 entries. Each pixel in the bitmap is represented by a 4-bit index into the color table. 
	   For example, if the first byte in the bitmap is 0x1F, the byte represents two pixels. 
	   The first pixel contains the color in the second table entry, and the second pixel contains 
	   the color in the sixteenth table entry. 
    8: The bitmap has a maximum of 256 colors, and the bmiColors member of BITMAPINFO contains up 
	   to 256 entries. In this case, each byte in the array represents a single pixel. 
   16: The bitmap has a maximum of 2^16 colors. If the biCompression member of the BITMAPINFOHEADER 
       is BI_RGB, the bmiColors member of BITMAPINFO is NULL. Each WORD in the bitmap array represents 
	   a single pixel. The relative intensities of red, green, and blue are represented with five bits for 
	   each color component. The value for blue is in the least significant five bits, followed by five 
	   bits each for green and red. The most significant bit is not used. The bmiColors color table is 
	   used for optimizing colors used on palette-based devices, and must contain the number of entries 
	   specified by the biClrUsed member of the BITMAPINFOHEADER. 
       If the biCompression member of the BITMAPINFOHEADER is BI_BITFIELDS, the bmiColors member contains 
	   three DWORD color masks that specify the red, green, and blue components, respectively, 
	   of each pixel. Each WORD in the bitmap array represents a single pixel.

	   Windows NT/Windows 2000/XP: When the biCompression member is BI_BITFIELDS, bits set in each DWORD
	                               mask must be contiguous and should not overlap the bits of another mask. 
								   All the bits in the pixel do not have to be used. 
	   
	   Windows 95/98/Me: When the biCompression member is BI_BITFIELDS, the system supports only the 
	                     following 16bpp color masks: A 5-5-5 16-bit image, where the blue mask is 0x001F, 
						 the green mask is 0x03E0, and the red mask is 0x7C00; and a 5-6-5 16-bit image, 
						 where the blue mask is 0x001F, the green mask is 0x07E0, and the red mask is 0xF800.
   24: The bitmap has a maximum of 2^24 colors, and the bmiColors member of BITMAPINFO is NULL. 
       Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green, 
	   and red, respectively, for a pixel. The bmiColors color table is used for optimizing colors 
	   used on palette-based devices, and must contain the number of entries specified by the biClrUsed 
	   member of the BITMAPINFOHEADER.  
   32: The bitmap has a maximum of 2^32 colors. If the biCompression member of the BITMAPINFOHEADER is 
       BI_RGB, the bmiColors member of BITMAPINFO is NULL. Each DWORD in the bitmap array represents 
	   the relative intensities of blue, green, and red, respectively, for a pixel. The high byte in 
	   each DWORD is not used. The bmiColors color table is used for optimizing colors used on 
	   palette-based devices, and must contain the number of entries specified by the biClrUsed member 
	   of the BITMAPINFOHEADER. 
	   If the biCompression member of the BITMAPINFOHEADER is BI_BITFIELDS, the bmiColors member contains 
	   three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. 
	   Each DWORD in the bitmap array represents a single pixel.
	   
	   Windows NT/ 2000: When the biCompression member is BI_BITFIELDS, bits set in each DWORD mask must 
	                     be contiguous and should not overlap the bits of another mask. All the bits in the
						 pixel do not need to be used.
	  Windows 95/98/Me: When the biCompression member is BI_BITFIELDS, the system supports only the following
	                    32-bpp color mask: The blue mask is 0x000000FF, the green mask is 0x0000FF00, and 
						the red mask is 0x00FF0000. 
	*/
	pbmpih->biBitCount      = biBitCount;   
	/* 30~33：指定是否压缩， （如果压缩了）采用的压缩格式。
	可以为： BI_RGB、BI_RLE4、BI_RLE8、BI_BITFIELDS、BI_PNG、BI_JPEG
	有的位图会进行游程长度编码：BI_RLE4、BI_RLE8 
	压缩可以节省空间， 但不便于编程读写。BI_RGB表示不进行压缩处理
	MSDN: Specifies the type of compression for a compressed bottom-up bitmap 
	(top-down DIBs cannot be compressed). This member can be one of the following values. 
    BI_RGB:  An uncompressed format. 
    BI_RLE8: A run-length encoded (RLE) format for bitmaps with 8 bpp. The compression format 
	         is a 2-byte format consisting of a count byte followed by a byte containing a color index. 
			 For more information, see Bitmap Compression.  
    BI_RLE4: An RLE format for bitmaps with 4 bpp. The compression format is a 2-byte format
	         consisting of a count byte followed by two word-length color indexes. 
			 For more information, see Bitmap Compression. 
    BI_BITFIELDS: Specifies that the bitmap is not compressed and that the color table consists
	              of three DWORD color masks that specify the red, green, and blue components, 
				  respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps. 
    BI_JPEG: Windows 98/Me, Windows 2000/XP: Indicates that the image is a JPEG image. 
    BI_PNG: Windows 98/Me, Windows 2000/XP: Indicates that the image is a PNG image. 
	
	*/
	pbmpih->biCompression  = BI_RGB; 
	/* 34~37: 位图数据区所占字节数，有固定的计算公式 
	MSDN: Specifies the size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps. 
    Windows 98/Me, Windows 2000/XP: If biCompression is BI_JPEG or BI_PNG, 
	biSizeImage indicates the size of the JPEG or PNG image buffer, respectively.*/
	pbmpih->biSizeImage     = ((((pbmpih->biWidth * pbmpih->biBitCount) + 31) & ~31) / 8) * pbmpih->biHeight;
	/* 38~41: 位图水平分辨率，每米像素数
	MSDN: Specifies the horizontal resolution, in pixels-per-meter, 
	of the target device for the bitmap. An application can use this value 
	to select a bitmap from a resource group that best matches the characteristics of the current device. */
	pbmpih->biXPelsPerMeter = 0L;
	/* 42~45: 位图垂直分辨率，每米像素数
	MSDN: Specifies the vertical resolution, in pixels-per-meter, of the target device for the bitmap.*/
	pbmpih->biYPelsPerMeter = 0L;
	/* 46~49: 位图实际使用颜色表中颜色数（对于有调色板的位图来说实际上是调色板中颜色项数，
	24位真彩色位图不需要调色板， 设为0， 8位灰度位图为256（2^8种颜色）。
	MSDN：If this value is zero, the bitmap uses the maximum number of colors corresponding 
	to the value of the biBitCount member for the compression mode specified by biCompression. */
	pbmpih->biClrUsed      = 0L;      
	/* 50~53: 显示位图所需颜色数
	MSDN： Specifies the number of color indexes that are required for displaying the bitmap. 
	If this value is zero, all colors are required. */
	pbmpih->biClrImportant = 0L;      
}

void SetBmpFileHeader(PBITMAPFILEHEADER pbmpfh, const PBITMAPINFOHEADER pbmpih)
{
	/* 0~1: 固定值： "BM"（或0x4D42），即表明这是位图（一般以bmp为文件名后缀）
	MSDN: Specifies the file type, must be BM. 
	*/
	pbmpfh->bfType      = *(WORD *)"BM"; 
	/* 2~5: 位图文件总大小（占用总字节数， 包括文件头、信息头、调色板、位图数据区占用字节数）
	MSDN: Specifies the size, in bytes, of the bitmap file. 
	*/
	pbmpfh->bfSize      = pbmpih->biSizeImage + 54 + pbmpih->biClrUsed * sizeof(RGBQUAD);     
	/* 6~7: 固定值0： 目前没什么用， 可能留作将来扩展。也有的结构体中有这样的域是为了内存对齐 
	MSDN: Reserved; must be zero. 
	*/
	pbmpfh->bfReserved1 = 0;   
	/* 8~9: 固定值 
	MSDN: Reserved; must be zero. 
	*/
	pbmpfh->bfReserved2 = 0;    
	/* 10~13: 位图数据区起始位置， 计算方法为：
	 位图文件头14个字节+位图信息头40个字节+位图调色板所占字节数， 
	 这里要创建的是一张24位位图（无调色板），故设置为54 也可以。
	MSDN: Specifies the offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to 
	the bitmap bits. 
	*/
	pbmpfh->bfOffBits   = 54 + pbmpih->biClrUsed * sizeof(RGBQUAD);     
}

void GenBmpImage(int width, int height, int colorDepth,COLORREF *RGBData, char *bmp)
{
    int h = 0, w = 0, i = 0;
	uint8_t *pBmp = bmp, *p = (uint8_t *)RGBData;
	int cd = colorDepth>>3;
    DWORD black = 0;
    int fillbits; 
    if ((colorDepth != 16) && (colorDepth != 24)) {
        return;
    }
	BITMAPFILEHEADER bmpfh = { 0 }; /* 位图文件头 */
	BITMAPINFOHEADER bmpih = { 0 }; /* 位图信息头 */
	SetBmpInfoHeader(&bmpih, width, height, colorDepth);
	SetBmpFileHeader(&bmpfh, &bmpih);
    fillbits = ( 4 - ( bmpih.biWidth * 3 ) % 4 ) % 4;

    memcpy(pBmp, &bmpfh, sizeof(BITMAPFILEHEADER));  /* 写入位图文件头 */
    pBmp += sizeof(BITMAPFILEHEADER);
    memcpy(pBmp, &bmpih, sizeof(BITMAPINFOHEADER)); /* 写入位图信息头 */
                                                     /* 写入调色板（如果有的话） */        
    pBmp += sizeof(BITMAPINFOHEADER);                                           
    printf("cd:%d\n", cd);
	/* 写入位图数据 */
	for (h = 0; h < height; ++h) {    
		for (w = 0; w < width; ++w) {
			memcpy(pBmp,p, cd);  /* 将像素值颜色写入位图文件 */
			pBmp += cd;
			p += cd;
		}
		/* 边界填充
		对于24位位图每个像素占3个字节，且每个扫描行所占字节数必须是4的倍数。
		比如，对于一张宽度为21个像素的24色位图， 理论上每扫描行占用21*3=63个字节，
		但63不是4的倍数，所以需要在该扫描行的最后填充一个字节的0，凑到64，
		这样实际上每扫描行占用64个字节。
		fillbits = ( 4 - ( biheader.biWidth * 3 ) % 4 ) % 4; 参考自acepig， 作用是
		计算每扫描行需要填充几个字节的0。对于宽度是4的倍数的图片， count为0。
		*/
		memcpy(pBmp, &black,fillbits);
	}
    return ;
}
int __main(void)
{

	FILE *fpBmp = NULL;
	int i;
	fpBmp = fopen("rendering.bmp", "wb");
	if (NULL == fpBmp) {
		perror("fopen failed:");
		exit(EXIT_FAILURE);
	}
    COLORREF bmpData[BMP_H*BMP_W];
    COLORREF bmp[BMP_H*BMP_W+40];
    for(i = 0; i < sizeof(bmpData)/sizeof(bmpData[0]); i++) {
        bmpData[i] = RGB(0xf0,0xca,0xa6); /* 天蓝色 */
    }
    GenBmpImage(BMP_W, BMP_H, 16, bmpData, (char*)bmp);
    fwrite(bmp, sizeof(bmp), 1, fpBmp);
	fclose(fpBmp);

	system("gthumb rendering.bmp");
	return 0;
}